/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once


#include "引擎枚举数据.h"

#include <线性代数/几何计算.h>

#include "面/面.h"
#include "材质/资产.h"
#include "纹理/纹理.h"
#include "UI主题.h"
#include "Input/Input.h"


#include <map>





#define DEF_拖放状态_准备		0
#define DEF_拖放状态_开始拖放	1
#define DEF_拖放状态_拖放		2
#define DEF_拖放状态_结束拖放	3


#define DEF_WIDGET_根布局 "widgetType_根布局"
#define DEF_WIDGET_对话框 "widgetType_对话框"


#define DEF_单色绘制ID(name)					\
	static uint16 gid_##name##绘制变换 = 0;		\
	static uint16 gid_##name##绘制颜色 = 0;		\
	static uint16 gid_##name##绘制元素 = 0;		\


#define DEF_文本绘制ID(name)					\
	static uint16 gid_##name##绘制变换 = 0;		\
	static uint16 gid_##name##绘制颜色 = 0;		\
	static uint16 gid_##name##绘制元素 = 0;		\
	static uint16 gid_##name##绘制文本 = 0;		\





enum E_UI绘制调整部分 {
	e_位置 = 1 << 0,
	e_大小 = 1 << 1,
	e_进入 = 1 << 2,
	e_退出 = 1 << 2,
	e_All = 0xffffffff,
};




typedef struct {
	uint16 id_变换;
	uint16 id_颜色;
	uint16 id_元素;
	uint16 id_图元;

	uint16 id_线属性;
}S_单色绘制ID;

typedef struct {
	uint16 id_变换;
	uint16 id_颜色;
	uint16 id_图元;
	uint16 id_线属性;

	uint16 id_元素;
}S_单色线绘制ID;

typedef struct {
	uint16 id_变换;
	uint16 id_边颜色;
	uint16 id_面颜色;
	uint16 id_边元素;
	uint16 id_面元素;
	uint16 id_图元;
}S_单色边面ID;

/*typedef struct {
	uint16 id_变换;
	uint16 id_颜色;
	uint16 id_元素;
	uint16 id_图元;
}S_纹理面绘制ID;*/

typedef struct {
	S_2D笔刷	笔刷;
	//S_Font		文字tex;
	uint16		id_变换;
	uint16		id_颜色;
	uint16		id_元素;
	//和 S_2D文本对象 文本ID 是同一个
	uint16		id_文本;
}S_单色文本绘制ID;

typedef struct {
	S_GPU内存块索引 id_变换;
	S_GPU内存块索引 id_颜色;
	S_GPU内存块索引 id_文本;
	uint16          层ID;
}S_行文本绘制ID;

typedef struct {
	S_GPU内存块索引 id_变换;
	S_GPU内存块索引 id_颜色;
	uint16          层ID;
}S_图标绘制ID;

typedef struct {
	ivec2 开始行列;
	ivec2 结束行列;
}S_文本选框区域ID;






typedef enum : uint8 {
	e_鼠标样式_默认,
	e_鼠标样式_横向双箭头,
	e_鼠标样式_纵向双箭头,
	e_鼠标样式_等待,
}E_鼠标样式;



typedef enum : uint8 {
	e_填充布局,
	e_HBOX布局,
	e_VBOX布局,
	e_BOX布局,
	e_网格,
}E_布局方式;

typedef enum : uint8 {
	e_左对齐,
	e_右对齐,
	e_据中对齐,
}E_对齐方式;

typedef enum : uint8 {
	e_读取,
	e_写入,
	e_关闭,
	e_打开路径,
}E_对话框类型;

typedef enum : uint8 {
	e_列表模式_垂直,
	e_列表模式_水平,
	e_列表模式_缩略,
}E_列表显示模式;



typedef struct {
	wchar_t 前;
	wchar_t 后;
}S_文本前后;







typedef void(*fp_Widget布局)(struct C_Widget* r, struct C_Widget** w, uint32 num);

typedef bool(*fp_Widget鼠标按键)(struct C_Widget* self, const E_鼠标按钮& 按钮);
typedef bool(*fp_Widget鼠标移动)(struct C_Widget* self, const ivec4& value);
typedef bool(*fp_Widget鼠标)(struct C_Widget* self, const S_鼠标& 鼠标);

typedef void(*fp_WidgetDraw)(struct C_Widget* self, struct S_2D画布* 画布);
typedef void(*fp_Widget动画)(struct C_Widget* self);
typedef void(*fp_Widget更新)(struct C_Widget* self);

typedef bool(*fp_Widget按键按下)(struct C_Widget* self, const S_键盘& ks);
typedef bool(*fp_Widget全局按键按下)(const S_键盘& ks);




typedef void(*fp_Widget变换修改)(struct C_Widget* self);

typedef bool(*fp_文件处理回调)(C_Widget* self, const std::vector<std::string>& name, E_对话框类型 方式);
typedef bool(*fp_打开关闭)(C_Widget* self, bool show);

typedef void(*fp_Widget文本输入回调)(struct C_Widget* r, wchar_t 前, wchar_t 中, wchar_t 后);
typedef void(*fp_Widget文本回调)(struct C_Widget* r, std::wstring& text);
typedef void(*fp_WidgetU8回调)(struct C_Widget* r, uint8 e);

typedef bool(*fp_Widget宽字符回调)(struct C_Widget* r, wchar_t text);
typedef void(*fp_Widget布尔值回调)(struct C_Widget* self, bool value);
//typedef void(*fp_Widget文本数值回调)(struct C_Widget* r, std::wstring& text);
typedef void(*fp_Widget绘制调整回调)(struct C_Widget* r, uint32 调整部分);

typedef struct C_Widget* (*fp_Widget添加回调)(struct C_Widget* r, uint32 当前同级组件数量);


typedef bool(*fp_列表项选中回调_str)(C_Widget* self, const std::vector<std::wstring>& name);



typedef struct {
	E_键位映射类型		m_Type;
	fp_Widget快捷键事件	event;
	struct C_Widget*	发生组件;
	uint8 键盘按键[4];
	uint8 键盘状态[4];
	uint8 记录;
	uint8 状态;
	uint8 连续;
}S_键盘键位映射;

typedef struct {
	E_键位映射类型		m_Type;
	fp_Widget快捷键事件	event;
	struct C_Widget*	发生组件;
	uint8 键盘按键[4];
	uint8 键盘状态[4];
	uint8 鼠标按键[4];
	uint8 鼠标状态[4];
	uint8 记录;
	uint8 状态;
	
	E_键位操作类型		操作类型;
}S_鼠标键位映射;

typedef struct {
	E_键位映射类型		m_Type;
	fp_Widget快捷键事件	event;
	struct C_Widget*	发生组件;

	uint8 键盘按键[4];
	uint8 键盘状态[4];
	uint8 鼠标按键[4];
	uint8 鼠标状态[4];

	uint8 记录;
	uint8 状态;
	
	E_拖放状态 拖放状态;
}S_拖拽键位映射;

typedef struct {
	E_键位映射类型		m_Type;
	fp_Widget快捷键事件	event;
	struct C_Widget* 发生组件;

	uint8 键盘按键[4];
	uint8 键盘状态[4];
	uint8 鼠标按键[4];
	uint8 鼠标状态[4];

	uint8 记录;
	uint8 状态;

	clock_t 开始计时;
	clock_t 结束计时;
}S_鼠标双击键位映射;


Inline S_鼠标键位映射* f_widget_init_鼠标键位映射() { 
	S_鼠标键位映射* km = (S_鼠标键位映射*)malloc(sizeof(S_鼠标键位映射));
	(*km) = { E_键位映射类型::e_键映射类型_鼠标, nullptr, nullptr, {},{},{},{},0, 0 };
	return km;
}
Inline S_鼠标双击键位映射* f_widget_alloc_鼠标双击键位映射() {
	S_鼠标双击键位映射* km = (S_鼠标双击键位映射*)malloc(sizeof(S_鼠标双击键位映射));
	(*km) = { E_键位映射类型::e_键映射类型_双击, nullptr, nullptr, {},{},{},{},0, 0, 0, 0 };
	return km;
}
Inline S_拖拽键位映射* f_widget_init_拖拽键位映射() { 
	S_拖拽键位映射* km = (S_拖拽键位映射*)malloc(sizeof(S_拖拽键位映射));
	(*km) = { E_键位映射类型::e_键映射类型_拖拽, nullptr, nullptr, {},{},{},{},0, 0 };
	return km;
}
Inline S_键盘键位映射* f_widget_init_键盘位映射() {
	S_键盘键位映射* km = (S_键盘键位映射*)malloc(sizeof(S_键盘键位映射));
	(*km) = { E_键位映射类型::e_键映射类型_键盘, nullptr, nullptr, {},{}, 0, false };
	return km;
}



typedef void(*fp_Layout)(struct C_Widget* self, struct C_Widget** ws, uint32 num);
struct S_布局器 {
	std::vector<S_布局器*>	m_子部件;
	//fp_Layout				mf_Layout;
	virtual void f_poll(struct C_Widget** ws, uint32 num) = 0;
};




typedef struct {
	struct C_Widget**	m_W;
	uint32				m_Num;
}S_需更新部件;
typedef S_需更新部件(*fp_getUpdateWidget)(struct C_Widget* self);

typedef struct {
	uint32	m_Type;
	void*	m_Next;
}S_拖放数据;
typedef E_事件是否传递(*fp_Widget拖放)(struct C_Widget* self, const S_鼠标& 鼠标, S_拖放数据& data);
typedef bool(*fp_Widget结束拖放)(struct C_Widget* self, struct C_Widget* 拾取的部件, S_拖放数据& data);





struct S_纹理组添加参数 {
	std::string m_GroupName;
	std::string m_Path;
};

typedef struct {
	uint16 m_元素开始索引;
	uint16 m_元素结束索引;

	uint32 m_实例开始索引;
	uint32 m_实例结束索引;
}S_绘制更新区间;

typedef struct {
	vec2	m_中心;
	vec2	m_比例;
	vec2	m_缩放后边界;
	vec2	m_大小;
	vec2	m_偏移比例;
}S_View属性;

typedef struct {
	uvec3	m_Dim;
	S_纹理*	m_Tex;
	uint8*	m_Data;
}S_纹理填充列队;

typedef struct {
	struct C_Widget*	m_rW;
	struct C_Widget*	m_aW;
	int32				m_Loc;
}S_部件添加列队;

typedef struct {
	struct C_Widget* m_W;
}S_关联组件;



struct ui_绘制模板 {
	enum E_绘制模板类型 : uint8 {
		e_画预设图形,
		e_画图标,
		e_画行文本,
	};
	E_绘制模板类型 m_模板类型;
	ui_绘制模板() : m_模板类型(E_绘制模板类型::e_画预设图形) {}
};


struct C_Widget {
	fp_WidgetDraw	mf_DrawFun;
	
	//布局可设置为并发属性执行 因此内部不能有GPU数据映射
	fp_Widget布局		mf_布局Fun;
	fp_Widget变换修改	mf_变换修改;
	fp_Widget动画		mf_动画更新;
	
	fp_getUpdateWidget	mf_get更新组件;


	fp_Widget鼠标按键	mf_鼠标按键按下;
	fp_Widget鼠标按键	mf_鼠标按键放开;
	fp_Widget鼠标按键	mf_鼠标按键点击;
	fp_Widget鼠标按键	mf_鼠标按键双击;
	fp_Widget鼠标		mf_鼠标滚轮;
	fp_Widget鼠标移动	mf_鼠标移动;
	fp_Widget拖放		mf_拖拽;
	fp_Widget拖放		mf_开始拖拽;
	fp_Widget结束拖放	mf_结束拖拽;

	fp_Widget鼠标	mf_鼠标进入;
	fp_Widget鼠标	mf_鼠标离开;
	//fp_Widget按键按下	mf_按键按下;
	//fp_Widget按键按下	mf_按键放开;
	fp_Widget按键按下	mf_键盘按键敲击;
	fp_文件处理回调	    mf_文件处理回调;
	
	
	fp_Widget绘制调整回调	mf_当前部件属性修改;	//废弃
	fp_打开关闭				mf_打开关闭;

	C_Widget(S_UI创建环境* ctx = 0);
	virtual ~C_Widget();


	virtual void f_setPos(vec2 pos);
	virtual void f_setSize(vec2 size);
	virtual void f_setMinSize(vec2 size);
	//virtual void f_Show(bool open);

	void f_setOriginalPos(vec2 pos);
	void f_setOriginalSize(vec2 pos);

	void f_setX(float32 x);
	void f_setY(float32 y);
	void f_setW(float32 w);
	void f_setH(float32 h);


	vec2 f_getPos() const;
	vec2 f_getSize() const;
	vec2 f_getOriginalPos() const;
	vec2 f_getOriginalSize() const;
	S_Rect2Df f_getRect() { return {m_Pos, m_Size}; }

	struct C_Widget管理* f_get窗口管理();


	uint32			f_get子部件数量() { return uint32(m_子组件.size()); }
	S_需更新部件	f_get更新部件();
	C_Widget*		f_get子组件(uint32 id);

	void f_裁剪(); //const vec4& area
	void f_重置布局(const vec4& area);
	void f_绘图(struct C_Widget* 画布, S_板载缓存* 投影矩阵);

	virtual void f_添加子组件(C_Widget* w, int32 loc = -1);
	virtual void f_销毁子组件(int32 id);
	void	f_替换子组件(int32 id, C_Widget* w);
	void	f_属性更新();
	void	f_标记为引用画布() { m_引用画布 = true; }
	void	f_标记区域更新() { m_绘制属性更新 = true; }
	void	f_绑定窗口管理(C_Widget管理* gm);
	


	std::vector<ui_绘制模板*> m_绘图模板;

	std::wstring	m_WName;
	std::string		m_TypeName;
	std::string		m_ICO;
	uvec2			m_图元;

	vec2		m_Pos;
	vec2		m_Size;
	vec2		m_Scale;
	vec2		m_MinSize;
	vec2		m_GlobalLoc;
	vec2		m_文本对齐偏移;

	bool		m_开启渲染;
	bool		m_被裁剪;
	bool		m_显示;
	
	bool		m_绘制属性更新;
	bool		m_GPU参数重置;
	//bool		m_是否被绘制;


	float32		m_延申比;
	bvec2		m_是否延展;
	int8		m_间隔宽度;
	E_布局方式  m_布局方式;

	S_关联组件* m_关联组件;


	static E_鼠标样式	g_鼠标样式;
	static S_鼠标		g_鼠标;
	static int8			g_焦点数量;
	static bool			g_是否打开了弹出窗口;
	static bool			G清除焦点组件;
	static std::set<S_键位映射*> G键位映射容器;


	//================ 扩展属性 =================
	S_View属性*		m_扩展视口属性;


	//================= 注册按键表 =====================
	std::vector<S_键位映射*>	m_键位映射;


	C_Widget*				m_父部件;
	//S_2D文本对象			m_文本对象;
	std::vector<C_Widget*>	m_子组件;
	vec4					m_裁剪大小;

	
	S_UI创建环境*			m_UIctx;
	S_2D画布*				m_画布;
	C_Widget*				m_画布所在部件;
	S_绘制更新区间*			m_子部件绘制区间;
	uint8					m_DPI;
	
	uint32					m_实例ID;


	//uint16					m_GPU内存偏移;
	//uint16					m_GPU文本字符内存偏移;
	//uint16					m_GPU文本变换内存偏移;
	//S_板载缓存*				m_变换矩阵;
	S_RGBA8UI				m_颜色A;
	S_RGBA8UI				m_颜色B;
	S_RGBA8UI				m_颜色C;

	S_Props_UI* m_PropUILink;
protected:
	//bool	m_是否重绘;
	bool	m_子部件裁剪使用父裁剪区域;

	vec2	m_OriginalPos;
	vec2	m_OriginalSize;

private:
	vec2	m_绘制区域;
	//__m128	m_Pos;
	//__m128	m_area;
	//vec4		m_裁剪Area;
	bool	m_引用画布;
	C_Widget管理* m_GM;
};








typedef void(*fp_部件更新阶段回调)();


struct C_Widget管理 {
	S_UI创建环境*	m_UICtx;
	C_Widget*		m_Root;
	uint8			m_GPU;

	S_布局器*		m_根布局器;

	C_Widget*		m_当前拖拽部件;
	C_Widget*		m_当前操作部件;
	
	S_拖放数据		m_拖放数据;

	C_Widget*		m_顶层窗口;
	uint16			m_顶层数量;

	S_绘图框架*		m_绘图框架;

	S_板载缓存*		m_投影矩阵;
	S_渲染参数		m_渲染参数;

	S_结构对象指针	m_视口GPU参数设置;
	S_Viewport	视口;
	S_Rect2D	裁剪;
	vec4		窗口大小;
	C_Widget*	mui_窗口;


	uint8 鼠标按键状态[8];
	//uint8 鼠标左键状态;
	//uint8 鼠标中键状态;
	//uint8 鼠标右键状态;
	uint8 拖放状态;

	bool 执行鼠标点击;
	bool 是否执行UI部件事件;
	bool 键盘按键向下传递;

	bool 鼠标左键按下传递;
	bool 鼠标左键放开传递;
	bool 鼠标右键按下传递;
	bool 鼠标右键放开传递;
	bool 鼠标中键按下传递;
	bool 鼠标中键放开传递;

	bool 有输入事件;

	std::vector<C_Widget*>			m_帧渲染层;
	std::vector<C_Widget*>			m_根部件切换组;
	std::vector<S_纹理填充列队>		m_纹理填充列队;
	C_Widget*						m_上一次焦点组件[128];
	int16							m_上一次焦点组件数量;
	C_Widget*						m_焦点组件[128];



	fp_部件更新阶段回调				mf_输入执行前回调;
	fp_部件更新阶段回调				mf_输入执行后回调;

	static std::vector<std::wstring> m_拖放文件名;

	C_Widget管理(S_UI创建环境& Ctx);

	void	f_绘制子组件(C_Widget* data, S_渲染参数 参数);
	void	f_加载图标(std::string 组名称, std::string path);
	

private:
	
	
	

};







typedef void(*fp_Widget文本输入完成)(C_Widget* self);

class C_文本框 : public C_Widget {

protected:
	S_文档文本		m_内部文档;
	
public:
	C_文本框(S_UI创建环境& ctx, std::string 字体名称);
	~C_文本框();

	uint16 m_字行距;
	uint16 m_字间距;


	S_文档文本*		m_文档;
	std::wstring	m_Text;
	
	vec2			m_行选框左边和右边;
	vec2			m_文字边间距;
	//未处理先后循序
	S_文本选框区域ID	m_选取;
	ivec2				m_光标;

	bool			m_开启编辑;
	bool			m_选择开启;
	E_对齐方式		m_对齐方式;


	const S_Font*	m_字体;
	static uvec2	g_选择文本ID区间;
	static vec2		g_光标绘制位置;
	static C_文本框* g当前操作文本框;

	fp_Widget文本回调		mf_文本输入;
	fp_Widget宽字符回调		mf_文本过滤;
	fp_Widget文本输入完成	mf_文本输入完成;

	fp_Widget更新	mf_框选时回调;
	fp_Widget更新	mf_框选后回调;

	virtual void	f_开启输入();
	virtual void	f_输入完成();

	void	f_set文本(const std::wstring& text);
	void	f_set光标绘制坐标();
	

	S_文本前后	f_get当前输入前后字符();
	wchar_t		f_get行头字符(int32 行);
	wchar_t		f_get行尾字符(int32 行);
	uint32		f_get同样字符数量(int32 行, int32 offset, wchar_t txt);
	
	
	
	virtual void	f_插入字符(wchar_t t, ivec2 pos) {}
	virtual void	f_删除字符(ivec2 pos) {}
	virtual void	f_删除字符() {}
	virtual void	f_插入行(uint32 pos) {}
	virtual void	f_删除行(uint32 pos) {}
	virtual void	f_set光标() {}
	virtual void	f_set插入文本(std::vector<std::wstring> texts) {}
	virtual void	f_Copy() {}
	virtual void	f_set对齐偏移();
};




class C_项面板项 : public C_Widget {
public:
	S_列表填充数据		m_项;
	fp_列表项选中回调	m_项选中回调;

	C_项面板项() : m_项选中回调(nullptr) {}
	//~C_弹出面板项() {}
};





void f_widget_裁剪组件(const vec2& pos, const vec4& 裁剪area, C_Widget* w);
void f_widget_裁剪组件_avx(const vec2& pos, const vec4& area, C_Widget** ws, uint8 num=8);

void f_widget_单个部件裁剪(C_Widget* w, const vec4& 父area, const vec2& 父全局坐标);

int8 f_widget_筛选焦点组件_avx(C_Widget** ws, uint8 num, const vec2& point);


void f_widget_remove子部件(C_Widget* self, int32 s, int32 e = -1, bool 即时销毁=true);
void f_widget_remove子部件(C_Widget* self, uint32* id, uint32 num, bool 即时销毁 = true);
void f_widget_remove子部件(C_Widget* self, std::vector<C_Widget*>& ws, bool 即时销毁=true);
void f_widget_remove子部件(C_Widget* self, C_Widget** ws, uint32 num, bool 即时销毁=true);
void f_widget_remove所有子部件(C_Widget* self, bool 即时销毁=true);

void f_widget_push待销毁部件(C_Widget** ws, uint32 num);
bool f_widget_待销毁部件清理();


void f_widget_push待添加部件(C_Widget* r, C_Widget** ws, uint32 num, int32 offset, bool 即时执行 = false);
void f_widget_push待添加部件(C_Widget* r, C_Widget* ws, int32 loc, bool 即时执行 = false);
void f_widget_执行待添加部件();
void f_widget_添加子组件(C_Widget* self, std::vector<C_Widget*>& ws, bool 即时执行 = true);

void f_widget_关联组件(C_Widget* r, C_Widget* s);
void f_widget_clear焦点组件();

uint32 f_widget_取组件位置索引(C_Widget* self, C_Widget* 要查找的组件);
void f_widget_移动层(C_Widget* self, uint32 源组件位置索引, uint32 目标位置索引);




/****************************************************************
*           顶层窗口
*****************************************************************/
uint8			f_widget_弹出顶层窗口(C_Widget* w);
uint8			f_widget_顶层窗口_push(C_Widget* w, uint8 offset);
uint8			f_widget_顶层窗口_pop();
uint8			f_widget_顶层窗口_pop(uint8 num);
S_需更新部件	f_widget_getTop();
C_Widget*		f_widget_getBack();
uint8			f_widget_getTopNum();









//void f_裁剪(__m128& area);
#define f_widget_get鼠标局部位置(pos, w) ( pos - ((w)->m_GlobalLoc) )
#define f_widget_转换坐标到原始坐标(pos, w) ( (pos) / ((w)->m_Scale.x) )


#define 部件画布(w) (w).m_画布









/****************************************************************
*						 扩展属性预设
*****************************************************************/
inline void f_Widget_计算偏移比例(C_Widget* self) {
	//vec2 一半大小 = vec_multi(self->m_扩展视口属性->m_边界, 0.5f);
	vec2 一半大小 = vec_mul(self->m_Size, 0.5f);

	self->m_扩展视口属性->m_大小 = self->m_Size;

	//float32 左边距离 = (self->m_扩展视口属性->m_中心.x) + 一半大小.x;
	//float32 顶边距离 = (self->m_扩展视口属性->m_中心.y) + 一半大小.y;
	float32 左边距离 = (self->m_扩展视口属性->m_中心.x);
	float32 顶边距离 = (self->m_扩展视口属性->m_中心.y);
	self->m_扩展视口属性->m_偏移比例.x = 左边距离 / self->m_Size.x;
	self->m_扩展视口属性->m_偏移比例.y = 顶边距离 / self->m_Size.y;
}


inline void f_widget_开启视口属性(C_Widget* self) {
	self->m_扩展视口属性 = (S_View属性*)malloc(sizeof(S_View属性));
	*(self->m_扩展视口属性) = { {}, {1,1}, {2048,2048}, {2048,2048}, {0.5f, 0.5f} };
	//f_Widget_计算偏移比例(self);
}




inline void f_C_Widget_鼠标位置视口缩放(C_Widget* self, const vec2& 缩放量) {
	auto 鼠标局部位置 = f_widget_get鼠标局部位置(C_Widget::g_鼠标.gPos, self);
	鼠标局部位置 = 鼠标局部位置 - self->m_扩展视口属性->m_中心;
	auto 比例 = 鼠标局部位置 / self->m_扩展视口属性->m_缩放后边界;
	//std::cout<<"缩放量 = "<< 缩放量.x << std::endl;

	self->m_扩展视口属性->m_比例 = self->m_扩展视口属性->m_比例 * 缩放量;

	if(self->m_扩展视口属性->m_比例.x < 0.00001) self->m_扩展视口属性->m_比例.x = 0.00001;
	if(self->m_扩展视口属性->m_比例.y < 0.00001) self->m_扩展视口属性->m_比例.y = 0.00001;

	if(self->m_扩展视口属性->m_比例.x > 100000) self->m_扩展视口属性->m_比例.x = 100000;
	if(self->m_扩展视口属性->m_比例.y > 100000) self->m_扩展视口属性->m_比例.y = 100000;


	vec2 新久边界差 = self->m_扩展视口属性->m_缩放后边界;
	self->m_扩展视口属性->m_缩放后边界 = self->m_扩展视口属性->m_大小 * self->m_扩展视口属性->m_比例;
	新久边界差 = self->m_扩展视口属性->m_缩放后边界 - 新久边界差;

	self->m_扩展视口属性->m_中心 = self->m_扩展视口属性->m_中心 - (新久边界差 * 比例);
	
	f_Widget_计算偏移比例(self);
	self->m_绘制属性更新 = true;
}

Inline void f_C_Widget_鼠标位置视口缩放(C_Widget* self) {
	auto 鼠标局部位置 = f_widget_get鼠标局部位置(C_Widget::g_鼠标.gPos, self);
	鼠标局部位置 = 鼠标局部位置 - self->m_扩展视口属性->m_中心;
	auto 比例 = 鼠标局部位置 / self->m_扩展视口属性->m_缩放后边界;
	//std::cout<<"缩放量 = "<< 缩放量.x << std::endl;

	vec2 新久边界差 = self->m_扩展视口属性->m_缩放后边界;
	self->m_扩展视口属性->m_缩放后边界 = self->m_扩展视口属性->m_大小 * self->m_扩展视口属性->m_比例;
	新久边界差 = self->m_扩展视口属性->m_缩放后边界 - 新久边界差;

	self->m_扩展视口属性->m_中心 = self->m_扩展视口属性->m_中心 - (新久边界差 * 比例);
	//self->m_扩展视口属性->m_边界 = 新边界;

	f_Widget_计算偏移比例(self);
	self->m_绘制属性更新 = true;
}

void f_Widget_计算视口缩放保持偏移比例(C_Widget* self);

void f_Widget_视口偏移(C_Widget* self, float32 x, float32 y);

inline vec2 f_Widget_getOriginal(const vec2& value, const vec2& scale) {
	return value / scale;
}

inline void f_Widget_应用视口缩放(C_Widget* self, C_Widget* view) {
	//view->f_setLoc(view->f_getOriginalPos() * self->m_扩展视口属性->m_比例 + self->m_扩展视口属性->m_中心);
	//view->f_setSize(view->f_getOriginalSize() * self->m_扩展视口属性->m_比例);
	//std::cout << "self->m_扩展视口属性->m_比例 = " << view << " + " << view->m_Size.x <<std::endl;
	view->f_setSize(self->m_Size);
	//self->m_扩展视口属性->m_偏移比例;
	view->m_Scale = self->m_扩展视口属性->m_比例;
}

Inline void f_Widget_鼠标位置视口缩放(C_Widget* self, const vec2& 鼠标位置, const vec2& 步进) {
	self->m_扩展视口属性->m_比例.x *= 步进.x;
	self->m_扩展视口属性->m_比例.y *= 步进.y;
	//self->f_setSize(self->m_Size);
	//self->m_扩展视口属性->m_偏移比例;
	self->m_Scale = self->m_扩展视口属性->m_比例;
}

inline void f_Widget_应用视口移动(C_Widget* self, C_Widget* view) {
	//view->f_setLoc(view->f_getOriginalPos() * self->m_扩展视口属性->m_比例 + self->m_扩展视口属性->m_中心);
	self->m_绘制属性更新 = true;
}


void f_Widget_应用视口滚动(C_Widget* self, C_Widget* view, E_方向 方向);
void f_Widget_限定视口滚动(C_Widget* self, float32 父组件大小, float32* view, E_方向 方向, float32 s);
void f_widget_移除组件链接(C_Widget* self);
void f_widget_移除组件链接(std::vector<C_Widget*>& ws);

void f_widget_属性链接组件(S_Props& prop, const std::vector<C_Widget*>& ws);
void f_widget_属性断开组件(S_Props& prop, const std::vector<C_Widget*>& ws);



typedef struct {
	vec2 选框左边右边;
	uvec2 选中文本区间;
}S_文本选框;


//返回光标在鼠标后位置  鼠标在字符1位置 返回0
vec2	f_widget_取鼠标在后光标位置(C_文本框* self, const vec2& 鼠标位置, E_对齐方式 对齐方式, vec2 offset, const std::wstring& text);
//返回光标在鼠标后位置  鼠标在字符0位置 返回1
vec2	f_widget_取鼠标在前光标位置(C_文本框* self, const vec2& 鼠标位置, E_对齐方式 对齐方式, vec2 offset, const std::wstring& text);
//S_文本选框	f_widget_选择编辑文本(C_文本框* self, const vec2& 光标位置);
void	f_widget_选择编辑文本(C_文本框* self, const uvec2& 区间);
uint16	f_ui_编辑文本(C_Widget* self, uint16 光标位置, const S_输入环境& input, E_对齐方式 对齐方式, vec2 offset, std::wstring& text);






//void f_ui_set鼠标样式(E_鼠标样式 样式);
void			f_widget_开始输入法();
void			f_widget_结束输入法();
void			f_widget_结束输入状态();
bool			f_widget_输入法是否有输入();
ivec2			f_widget_get输入法窗口位置();
void			f_widget_发射输入法文本(const std::wstring& str);
void			f_widget_set编辑框输入法窗口位置(const ivec2& pos);
std::wstring	f_widget_get输入法文本();
bool			f_widget_是否处在输入法状态();
void			f_widget_set当前正在输入的文本(const std::wstring& txt);
void            f_widget_拷贝文本();



void		f_widget_set当前窗口矩形(const vec4& 区域);
vec4		f_widget_get当前窗口矩形();



void		f_widget_交换顶层组件(C_Widget管理* gm, uint32 新顶层组件ID);
void		f_widget_交换顶层组件(C_Widget* w, uint32 新顶层组件ID);

Inline vec2 f_widget_限制组件大小(C_Widget* self) {
	vec4 窗口大小 = f_widget_get当前窗口矩形();
	if (self->m_Size.x > 窗口大小.z - 窗口大小.x) {
		self->m_Size.x = 窗口大小.z - 窗口大小.x;
	}
	if (self->m_Size.y > 窗口大小.w - 窗口大小.y) {
		self->m_Size.y = 窗口大小.w - 窗口大小.y;
	}
	return {};
}

Inline vec2 f_widget_弹出窗口坐标矫正(C_Widget* self, vec2 pos) {
	auto e = self->f_get更新部件();
	if(e.m_Num) self->mf_布局Fun(self, e.m_W, e.m_Num);
	//vec4 当前菜单大小 = self->m_裁剪大小;
	vec4 窗口大小 = f_widget_get当前窗口矩形();

	if (pos.x + self->m_Size.x >= 窗口大小.z) {
		pos.x = 窗口大小.z - self->m_Size.x;
	}
	if (pos.x < 0) pos.x = 0;

	if (pos.y + self->m_Size.y >= 窗口大小.w) {
		pos.y = 窗口大小.w - self->m_Size.y;
		
	}
	if (pos.y < 0) pos.y = 0;

	return pos;
}

DWORD WINAPI f_widget_定时关闭弹出组件(LPVOID pParam);
void f_widget_线程定时关闭弹出组件(int32 延时 = 600);
void f_widget_取消定时关闭弹出组件();



void f_widget_set鼠标位置(const vec2* pos);









//class C_键位映射配置 {
//public:
//	C_键位映射配置();
//
//	static std::map<S_键位映射*, S_Props> g_全局键位映射容器;
//	static std::map<S_键位映射*, S_Props> g_3D视口键位映射容器;
//	static std::map<S_键位映射*, S_Props> g_2D视口键位映射容器;
//	static std::map<S_键位映射*, S_Props> g_节点视口键位映射容器;
//
//	static void f_添加全局操作键位(S_键位映射* key, std::wstring name);
//	static void f_添加3D视口操作键位(S_键位映射* key, std::wstring name);
//	static void f_添加2D视口操作键位(S_键位映射* key, std::wstring name);
//	static void f_添加节点视口操作键位(S_键位映射* key, std::wstring name);
//
//	static void f_销毁键位映射();
//};
////void on_文件菜单项(C_Widget* self, const std::wstring name, uint16 id);
//
//
//void f_配置_添加操作键位(S_键位映射* key, uint32 分组 = 0);
//
////void f_配置_添加3D视口操作键位(S_键位映射* key, uint32 分组 = 0);
//
//S_键位映射* f_配置_取操作键位(uint32 分组 = 0);








